home *** CD-ROM | disk | FTP | other *** search
- /* CAB -- an XAD client for extracting Microsoft Cabinet files
- * (C) 2000 Stuart Caie <kyzer@4u.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
- /* Credits:
- * The CAB format, and MSZIP/LZX formats are described in the documents
- * CABFMT.DOC, LZXFMT.DOC and MSZIPFMT.DOC in the CAB SDK, which is
- * (C) 1997 Microsoft Corporation.
- *
- * MSZIP is a modification of the inflate and deflate methods created by
- * Phil Katz. LZX was created by Johnathan Forbes and Tomi Poutanen.
- *
- * The MSZIP part of this client was written for me by Dirk Stöcker, who
- * based it on code from InfoZip's free UnZip utility. Dirk also provided
- * extensive testing materials, feedback and moral support (oh - and he
- * created the XAD system :). I took the fast Huffman table builder from
- * David Tritscher's unlzx (no relation :) and adapted to my needs.
- */
-
- /* CAB has pretty much everything - multivolume archives, merged file data,
- * and multiple compression formats. 'Folders' store compressed data, and
- * may span several cabinets. 'Files' live as data inside a folder when
- * uncompressed. EOR checksums are used instead of CRCs. Four compression
- * formats are known - NONE, MSZIP, QUANTUM and LZX. NONE is obviously
- * uncompressed data. MSZIP is simply PKZIP's deflate/inflate algorithims
- * with 'CK' as a signature instead of 'PK'. QUANTUM is a complete unknown,
- * and isn't implemented in this client. LZX is a much loved LZH based
- * archiver in the Amiga world, the algorithim taken (bought?) by Microsoft
- * and tweaked for Intel code.
- */
-
- /* $VER: CAB.c 1.1 (05.08.2000) */
-
- #include "SDI_compiler.h"
- #include "ConvertE.c"
- #include <exec/types.h>
- #include <exec/memory.h>
- #include <string.h>
- #include <libraries/xadmaster.h>
- #include <proto/xadmaster.h>
-
- #ifdef DEBUG
- void KPrintF(char *fmt, ...);
- #define D(x) { KPrintF x ; }
- #else
- #define D(x)
- #endif
-
- #define CABSTATE struct CABstate *cabstate
- #define XADBASE REG(a6, struct xadMasterBase *xadMasterBase)
- #define CAB(x) (cabstate->x)
- #define ZIP(x) (cabstate->arcstate.zip.x)
- #define QTM(x) (cabstate->arcstate.qtm.x)
- #define LZX(x) (cabstate->arcstate.lzx.x)
-
- #define CABFILEFOL(fi) ((struct CABfolder *)(fi)->xfi_PrivateInfo)
-
- /* requires UBYTE buf[] */
- #define GETLONG(n) EndGetI32(&buf[n])
- #define GETWORD(n) EndGetI16(&buf[n])
- #define GETBYTE(n) buf[n]
-
- #ifndef XADMASTERFILE
- #define CAB_Client FirstClient
- #define NEXTCLIENT 0
- const UBYTE version[] = "$VER: CAB 1.1 (05.08.2000)";
- #endif
- #define CAB_VERSION 1
- #define CAB_REVISION 0
-
- /* work-doing macros */
-
- /* required: label exit_handler; struct xadArchiveInfo *ai; LONG err; */
-
- #define SKIP(offset) if ((err = xadHookAccess(XADAC_INPUTSEEK, \
- (ULONG)(offset), NULL, ai))) goto exit_handler
- #define SEEK(offset) SKIP((offset) - ai->xai_InPos)
-
- #define READ(buffer,length) if ((err = xadHookAccess(XADAC_READ, \
- (ULONG)(length), (APTR)(buffer), ai))) goto exit_handler
- #define WRITE(buffer,length) if ((err = xadHookAccess(XADAC_WRITE, \
- (ULONG)(length), (APTR)(buffer), ai))) goto exit_handler
-
- #define ERROR(error) { \
- D(("CAB: error " #error " line %ld\n", __LINE__)) \
- err = XADERR_##error; goto exit_handler; \
- }
- #define TAINT(reason) { \
- ai->xai_Flags |= XADAIF_FILECORRUPT; \
- D(("CAB: TAINT - " reason "\n")) \
- }
-
- #define ALLOC(t,v,l) \
- if (!((v) = (t) xadAllocVec((l),MEMF_CLEAR))) ERROR(NOMEMORY)
- #define ALLOCOBJ(t,v,kind,tags) \
- if (!((v) = (t) xadAllocObjectA((kind),(tags)))) ERROR(NOMEMORY)
- #define FREE(obj) xadFreeObjectA((obj),NULL)
-
- /*--------------------------------------------------------------------------*/
- /* our archiver information / state */
-
- /* MSZIP stuff */
-
- #define ZIPWSIZE 0x8000 /* window size--must be a power of two, and at least 32K for zip's deflate method */
- #define ZIPLBITS 9 /* bits in base literal/length lookup table */
- #define ZIPDBITS 6 /* bits in base distance lookup table */
- #define ZIPBMAX 16 /* maximum bit length of any code (16 for explode) */
- #define ZIPN_MAX 288 /* maximum number of codes in any set */
-
- struct Ziphuft {
- UBYTE e; /* number of extra bits or operation */
- UBYTE b; /* number of bits in this code or subcode */
- union {
- UWORD n; /* literal, length base, or distance base */
- struct Ziphuft *t; /* pointer to next level of table */
- } v;
- };
-
- struct CABZIPstate {
- ULONG window_posn; /* current offset within the window */
-
- ULONG bb; /* bit buffer */
- ULONG bk; /* bits in bit buffer */
- ULONG ll[288+32]; /* literal/length and distance code lengths */
- ULONG c[ZIPBMAX+1]; /* bit length count table */
- LONG lx[ZIPBMAX+1]; /* memory for l[-1..ZIPBMAX-1] */
- struct Ziphuft *u[ZIPBMAX]; /* table stack */
- ULONG v[ZIPN_MAX]; /* values in order of bit length */
- ULONG x[ZIPBMAX+1]; /* bit offsets, then code stack */
-
- UBYTE *inpos;
- };
-
-
- /* Quantum stuff - not supported yet */
- struct CABQTMstate {
- UBYTE *window; /* the actual decoding window */
- ULONG window_size; /* window size (4Kb through 2Mb) */
- ULONG actual_size; /* window size when it was first allocated */
- UWORD comp_level; /* level of compression */
- };
-
-
- /* LZX stuff */
-
- /* some constants defined by the LZX specification */
- #define LZX_MIN_MATCH (2)
- #define LZX_MAX_MATCH (257)
- #define LZX_NUM_CHARS (256)
- #define LZX_BLOCKTYPE_INVALID (0) /* also blocktypes 4-7 invalid */
- #define LZX_BLOCKTYPE_VERBATIM (1)
- #define LZX_BLOCKTYPE_ALIGNED (2)
- #define LZX_BLOCKTYPE_UNCOMPRESSED (3)
- #define LZX_PRETREE_NUM_ELEMENTS (20)
- #define LZX_ALIGNED_NUM_ELEMENTS (8) /* aligned offset tree #elements */
- #define LZX_NUM_PRIMARY_LENGTHS (7) /* this one missing from spec! */
- #define LZX_NUM_SECONDARY_LENGTHS (249) /* length tree #elements */
-
-
- /* LZX huffman defines: tweak tablebits as desired */
- #define LZX_PRETREE_MAXSYMBOLS (LZX_PRETREE_NUM_ELEMENTS)
- #define LZX_PRETREE_TABLEBITS (6)
- #define LZX_MAINTREE_MAXSYMBOLS (LZX_NUM_CHARS + 50*8)
- #define LZX_MAINTREE_TABLEBITS (12)
- #define LZX_LENGTH_MAXSYMBOLS (LZX_NUM_SECONDARY_LENGTHS+1)
- #define LZX_LENGTH_TABLEBITS (12)
- #define LZX_ALIGNED_MAXSYMBOLS (LZX_ALIGNED_NUM_ELEMENTS)
- #define LZX_ALIGNED_TABLEBITS (7)
-
- #define LZX_LENTABLE_SAFETY (64) /* we allow length table decoding overruns */
-
- #define LZX_DECLARE_TABLE(tbl) \
- UWORD tbl##_table[(1<<LZX_##tbl##_TABLEBITS) + (LZX_##tbl##_MAXSYMBOLS<<1)];\
- UBYTE tbl##_len [LZX_##tbl##_MAXSYMBOLS + LZX_LENTABLE_SAFETY]
-
-
- struct CABLZXstate {
- UBYTE *window; /* the actual decoding window */
- ULONG window_size; /* window size (32Kb through 2Mb) */
- ULONG actual_size; /* window size when it was first allocated */
- ULONG window_posn; /* current offset within the window */
- ULONG R0, R1, R2; /* for the LRU offset system */
- UWORD main_elements; /* number of main tree elements */
- BOOL header_read; /* have we started decoding at all yet? */
- UWORD block_type; /* type of this block */
- ULONG block_length; /* uncompressed length of this block */
- ULONG block_remaining; /* uncompressed bytes still left to decode */
- ULONG frames_read; /* the number of CFDATA blocks processed */
- LONG intel_filesize; /* magic header value used for transform */
- LONG intel_curpos; /* current offset in transform space */
- BOOL intel_started; /* have we seen any translatable data yet? */
-
- LZX_DECLARE_TABLE(PRETREE);
- LZX_DECLARE_TABLE(MAINTREE);
- LZX_DECLARE_TABLE(LENGTH);
- LZX_DECLARE_TABLE(ALIGNED);
- };
-
-
-
- /*--------------------------------------------------------------------------*/
- /* CAB structures */
-
- #define CFHEAD_SIGNATURE (('M') | ('S'<<8) | ('C'<<16) | ('F'<<24)) /*intel!*/
-
- #define cfhead_Signature (0x00)
- #define cfhead_Reserved1 (0x04)
- #define cfhead_CabinetSize (0x08)
- #define cfhead_Reserved2 (0x0C)
- #define cfhead_FileOffset (0x10)
- #define cfhead_Reserved3 (0x14)
- #define cfhead_MinorVersion (0x18)
- #define cfhead_MajorVersion (0x19)
- #define cfhead_NumFolders (0x1A)
- #define cfhead_NumFiles (0x1C)
- #define cfhead_Flags (0x1E)
- #define cfhead_SetID (0x20)
- #define cfhead_CabinetIndex (0x22)
- #define cfhead_SIZEOF (0x24)
- #define cfheadext_HeaderReserved (0x00)
- #define cfheadext_FolderReserved (0x02)
- #define cfheadext_DataReserved (0x03)
- #define cfheadext_SIZEOF (0x04)
- /* cfhead_ReservedArea (== HeaderReserved bytes) */
- /* cfhead_PrevCabFile (null terminated string) */
- /* cfhead_PrevCabName (null terminated string) */
- /* cfhead_NextCabFile (null terminated string) */
- /* cfhead_NextCabName (null terminated string) */
-
- #define cffold_DataOffset (0x00)
- #define cffold_NumBlocks (0x04)
- #define cffold_CompType (0x06)
- #define cffold_SIZEOF (0x08)
- /* cffold_ReservedArea (== FolderReserved bytes) */
-
- #define cffile_UncompressedSize (0x00)
- #define cffile_FolderOffset (0x04)
- #define cffile_FolderIndex (0x08)
- #define cffile_Date (0x0A)
- #define cffile_Time (0x0C)
- #define cffile_Attribs (0x0E)
- #define cffile_SIZEOF (0x10)
- /* cffile_FileName (null terminated string) */
-
- #define cfdata_CheckSum (0x00) /* cksum of header/reserved/data */
- #define cfdata_CompressedSize (0x04) /* compressed size of block */
- #define cfdata_UncompressedSize (0x06) /* uncompressed size of block */
- #define cfdata_SIZEOF (0x08)
- /* cfdata_ReservedArea (== DataReserved bytes) */
-
- /* flags and values */
-
- #define cffoldCOMPTYPE_MASK (0x000f)
- #define cffoldCOMPTYPE_NONE (0x0000)
- #define cffoldCOMPTYPE_MSZIP (0x0001)
- #define cffoldCOMPTYPE_QUANTUM (0x0002)
- #define cffoldCOMPTYPE_LZX (0x0003)
-
- #define cfheadPREV_CABINET (0x0001)
- #define cfheadNEXT_CABINET (0x0002)
- #define cfheadRESERVE_PRESENT (0x0004)
-
- #define cffileCONTINUED_FROM_PREV (0xFFFD)
- #define cffileCONTINUED_TO_NEXT (0xFFFE)
- #define cffileCONTINUED_PREV_AND_NEXT (0xFFFF)
- #define cffileUTFNAME (0x80)
-
- #define CAB_NAMEMAX 512 /* maximum length of a single path/filename */
-
- /* CAB data blocks are <= 32768 bytes in uncompressed form. Uncompressed
- * blocks have zero growth. MSZIP guarantees that it won't grow above
- * uncompressed size by more than 12 bytes. LZX guarantees it won't grow
- * more than 6144 bytes.
- */
- #define CAB_BLOCKMAX (32768)
- #define CAB_INPUTMAX (CAB_BLOCKMAX+6144)
-
- /* maximum number of split blocks in any one folder */
- #define CAB_SPLITMAX (10)
-
- struct CABfolder {
- struct CABfolder *next;
-
- ULONG offsets[CAB_SPLITMAX]; /* offset of first/split data blocks */
- UBYTE data_res[CAB_SPLITMAX]; /* bytes reserved in block headers */
- ULONG comp_size; /* number of compressed bytes in this part */
- UWORD comp_type; /* compression format and window size */
- UWORD num_splits; /* number of split blocks */
- struct xadFileInfo *contfile; /* is this folder continuable? */
- };
-
- struct CABstate {
- struct xadMasterBase *xad; /* XAD library base */
- struct xadArchiveInfo *ai; /* archive we're extracting from */
- struct CABfolder *folders; /* linked list of all folders */
- struct CABfolder *current; /* current folder we're extracting from */
- ULONG offset; /* uncompressed offset within folder */
- UBYTE *outpos; /* (high level) start of data to use up */
- UWORD outlen; /* (high level) amount of data to use up */
- UBYTE split; /* at which split in current folder? */
-
- /* to speed up the arrival of an error message for trashed files */
- struct CABfolder *lastfolder;
- ULONG lastoffset;
- LONG lasterror;
-
- /* the chosen compression type functions */
- LONG (*decompress)(CABSTATE, int, int);
- void (*free)(CABSTATE);
-
- union {
- struct CABZIPstate zip;
- struct CABQTMstate qtm;
- struct CABLZXstate lzx;
- } arcstate;
-
- UBYTE inbuf[CAB_INPUTMAX], outbuf[CAB_BLOCKMAX];
- };
-
- /*--------------------------------------------------------------------------*/
- /* MSZIP decompressor */
-
- /* This part was written by Dirk Stöcker, based on the InfoZip deflate code */
-
- /* Tables for deflate from PKZIP's appnote.txt. */
- static const UBYTE Zipborder[] = /* Order of the bit length code lengths */
- { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
- static const UWORD Zipcplens[] = /* Copy lengths for literal codes 257..285 */
- { 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51,
- 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
- static const UWORD Zipcplext[] = /* Extra bits for literal codes 257..285 */
- { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4,
- 4, 5, 5, 5, 5, 0, 99, 99}; /* 99==invalid */
- static const UWORD Zipcpdist[] = /* Copy offsets for distance codes 0..29 */
- { 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385,
- 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577};
- static const UWORD Zipcpdext[] = /* Extra bits for distance codes */
- { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10,
- 10, 11, 11, 12, 12, 13, 13};
-
- /* And'ing with Zipmask[n] masks the lower n bits */
- static const UWORD Zipmask[17] = {
- 0x0000, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
- 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
- };
-
- #define ZIPNEEDBITS(n) {while(k<(n)){LONG c=*(ZIP(inpos)++);\
- b|=((ULONG)c)<<k;k+=8;}}
- #define ZIPDUMPBITS(n) {b>>=(n);k-=(n);}
-
- static LONG Ziphuft_free(CABSTATE, struct Ziphuft *t)
- {
- struct xadMasterBase *xadMasterBase = CAB(xad);
- register struct Ziphuft *p, *q;
-
- /* Go through linked list, freeing from the allocated (t[-1]) address. */
- p = t;
- while (p != (struct Ziphuft *)NULL)
- {
- q = (--p)->v.t;
- xadFreeObjectA(p, 0);
- p = q;
- }
- return 0;
- }
-
- static LONG Ziphuft_build(CABSTATE, ULONG *b, ULONG n, ULONG s, UWORD *d, UWORD *e, struct Ziphuft **t, LONG *m)
- {
- ULONG a; /* counter for codes of length k */
- ULONG el; /* length of EOB code (value 256) */
- ULONG f; /* i repeats in table every f entries */
- LONG g; /* maximum code length */
- LONG h; /* table level */
- register ULONG i; /* counter, current code */
- register ULONG j; /* counter */
- register LONG k; /* number of bits in current code */
- LONG *l; /* stack of bits per table */
- register ULONG *p; /* pointer into ZIP(c)[], ZIP(b)[], or ZIP(v)[] */
- register struct Ziphuft *q; /* points to current table */
- struct Ziphuft r; /* table entry for structure assignment */
- register LONG w; /* bits before this table == (l * h) */
- ULONG *xp; /* pointer into x */
- LONG y; /* number of dummy codes added */
- ULONG z; /* number of entries in current table */
- struct xadMasterBase *xadMasterBase = CAB(xad);
-
- l = ZIP(lx)+1;
-
- /* Generate counts for each bit length */
- el = n > 256 ? b[256] : ZIPBMAX; /* set length of EOB code, if any */
-
- for(i = 0; i < ZIPBMAX+1; ++i)
- ZIP(c)[i] = 0;
- p = b; i = n;
- do
- {
- ZIP(c)[*p]++; p++; /* assume all entries <= ZIPBMAX */
- } while (--i);
- if (ZIP(c)[0] == n) /* null input--all zero length codes */
- {
- *t = (struct Ziphuft *)NULL;
- *m = 0;
- return 0;
- }
-
- /* Find minimum and maximum length, bound *m by those */
- for (j = 1; j <= ZIPBMAX; j++)
- if (ZIP(c)[j])
- break;
- k = j; /* minimum code length */
- if ((ULONG)*m < j)
- *m = j;
- for (i = ZIPBMAX; i; i--)
- if (ZIP(c)[i])
- break;
- g = i; /* maximum code length */
- if ((ULONG)*m > i)
- *m = i;
-
- /* Adjust last length count to fill out codes, if needed */
- for (y = 1 << j; j < i; j++, y <<= 1)
- if ((y -= ZIP(c)[j]) < 0)
- return 2; /* bad input: more codes than bits */
- if ((y -= ZIP(c)[i]) < 0)
- return 2;
- ZIP(c)[i] += y;
-
- /* Generate starting offsets LONGo the value table for each length */
- ZIP(x)[1] = j = 0;
- p = ZIP(c) + 1; xp = ZIP(x) + 2;
- while (--i)
- { /* note that i == g from above */
- *xp++ = (j += *p++);
- }
-
- /* Make a table of values in order of bit lengths */
- p = b; i = 0;
- do{
- if ((j = *p++) != 0)
- ZIP(v)[ZIP(x)[j]++] = i;
- } while (++i < n);
-
-
- /* Generate the Huffman codes and for each, make the table entries */
- ZIP(x)[0] = i = 0; /* first Huffman code is zero */
- p = ZIP(v); /* grab values in bit order */
- h = -1; /* no tables yet--level -1 */
- w = l[-1] = 0; /* no bits decoded yet */
- ZIP(u)[0] = (struct Ziphuft *)NULL; /* just to keep compilers happy */
- q = (struct Ziphuft *)NULL; /* ditto */
- z = 0; /* ditto */
-
- /* go through the bit lengths (k already is bits in shortest code) */
- for (; k <= g; k++)
- {
- a = ZIP(c)[k];
- while (a--)
- {
- /* here i is the Huffman code of length k bits for value *p */
- /* make tables up to required level */
- while (k > w + l[h])
- {
- w += l[h++]; /* add bits already decoded */
-
- /* compute minimum size table less than or equal to *m bits */
- z = (z = g - w) > (ULONG)*m ? *m : z; /* upper limit */
- if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */
- { /* too few codes for k-w bit table */
- f -= a + 1; /* deduct codes from patterns left */
- xp = ZIP(c) + k;
- while (++j < z) /* try smaller tables up to z bits */
- {
- if ((f <<= 1) <= *++xp)
- break; /* enough codes to use up j bits */
- f -= *xp; /* else deduct codes from patterns */
- }
- }
- if ((ULONG)w + j > el && (ULONG)w < el)
- j = el - w; /* make EOB code end at table */
- z = 1 << j; /* table entries for j-bit table */
- l[h] = j; /* set table size in stack */
-
- /* allocate and link in new table */
- if (!(q = (struct Ziphuft *) xadAllocVec((z + 1)*sizeof(struct Ziphuft), MEMF_PUBLIC)))
- {
- if(h)
- Ziphuft_free(cabstate, ZIP(u)[0]);
- return 3; /* not enough memory */
- }
- *t = q + 1; /* link to list for Ziphuft_free() */
- *(t = &(q->v.t)) = (struct Ziphuft *)NULL;
- ZIP(u)[h] = ++q; /* table starts after link */
-
- /* connect to last table, if there is one */
- if (h)
- {
- ZIP(x)[h] = i; /* save pattern for backing up */
- r.b = (UBYTE)l[h-1]; /* bits to dump before this table */
- r.e = (UBYTE)(16 + j); /* bits in this table */
- r.v.t = q; /* pointer to this table */
- j = (i & ((1 << w) - 1)) >> (w - l[h-1]);
- ZIP(u)[h-1][j] = r; /* connect to last table */
- }
- }
-
- /* set up table entry in r */
- r.b = (UBYTE)(k - w);
- if (p >= ZIP(v) + n)
- r.e = 99; /* out of values--invalid code */
- else if (*p < s)
- {
- r.e = (UBYTE)(*p < 256 ? 16 : 15); /* 256 is end-of-block code */
- r.v.n = *p++; /* simple code is just the value */
- }
- else
- {
- r.e = (UBYTE)e[*p - s]; /* non-simple--look up in lists */
- r.v.n = d[*p++ - s];
- }
-
- /* fill code-like entries with r */
- f = 1 << (k - w);
- for (j = i >> w; j < z; j += f)
- q[j] = r;
-
- /* backwards increment the k-bit code i */
- for (j = 1 << (k - 1); i & j; j >>= 1)
- i ^= j;
- i ^= j;
-
- /* backup over finished tables */
- while ((i & ((1 << w) - 1)) != ZIP(x)[h])
- w -= l[--h]; /* don't need to update q */
- }
- }
-
- /* return actual size of base table */
- *m = l[0];
-
- /* Return true (1) if we were given an incomplete table */
- return y != 0 && g != 1;
- }
-
- static LONG Zipinflate_codes(CABSTATE, struct Ziphuft *tl, struct Ziphuft *td, LONG bl, LONG bd)
- {
- register ULONG e; /* table entry flag/number of extra bits */
- ULONG n, d; /* length and index for copy */
- ULONG w; /* current window position */
- struct Ziphuft *t; /* pointer to table entry */
- ULONG ml, md; /* masks for bl and bd bits */
- register ULONG b; /* bit buffer */
- register ULONG k; /* number of bits in bit buffer */
-
- /* make local copies of globals */
- b = ZIP(bb); /* initialize bit buffer */
- k = ZIP(bk);
- w = ZIP(window_posn); /* initialize window position */
-
- /* inflate the coded data */
- ml = Zipmask[bl]; /* precompute masks for speed */
- md = Zipmask[bd];
-
- for(;;)
- {
- ZIPNEEDBITS((ULONG)bl)
- if((e = (t = tl + ((ULONG)b & ml))->e) > 16)
- do
- {
- if (e == 99)
- return 1;
- ZIPDUMPBITS(t->b)
- e -= 16;
- ZIPNEEDBITS(e)
- } while ((e = (t = t->v.t + ((ULONG)b & Zipmask[e]))->e) > 16);
- ZIPDUMPBITS(t->b)
- if (e == 16) /* then it's a literal */
- CAB(outbuf)[w++] = (UBYTE)t->v.n;
- else /* it's an EOB or a length */
- {
- /* exit if end of block */
- if(e == 15)
- break;
-
- /* get length of block to copy */
- ZIPNEEDBITS(e)
- n = t->v.n + ((ULONG)b & Zipmask[e]);
- ZIPDUMPBITS(e);
-
- /* decode distance of block to copy */
- ZIPNEEDBITS((ULONG)bd)
- if ((e = (t = td + ((ULONG)b & md))->e) > 16)
- do {
- if (e == 99)
- return 1;
- ZIPDUMPBITS(t->b)
- e -= 16;
- ZIPNEEDBITS(e)
- } while ((e = (t = t->v.t + ((ULONG)b & Zipmask[e]))->e) > 16);
- ZIPDUMPBITS(t->b)
- ZIPNEEDBITS(e)
- d = w - t->v.n - ((ULONG)b & Zipmask[e]);
- ZIPDUMPBITS(e)
- do
- {
- n -= (e = (e = ZIPWSIZE - ((d &= ZIPWSIZE-1) > w ? d : w)) > n ? n : e);
- do
- {
- CAB(outbuf)[w++] = CAB(outbuf)[d++];
- } while (--e);
- } while (n);
- }
- }
-
- /* restore the globals from the locals */
- ZIP(window_posn) = w; /* restore global window pointer */
- ZIP(bb) = b; /* restore global bit buffer */
- ZIP(bk) = k;
-
- /* done */
- return 0;
- }
-
- static LONG Zipinflate_stored(CABSTATE) /* "decompress" an inflated type 0 (stored) block. */
- {
- ULONG n; /* number of bytes in block */
- ULONG w; /* current window position */
- register ULONG b; /* bit buffer */
- register ULONG k; /* number of bits in bit buffer */
-
- /* make local copies of globals */
- b = ZIP(bb); /* initialize bit buffer */
- k = ZIP(bk);
- w = ZIP(window_posn); /* initialize window position */
-
- /* go to byte boundary */
- n = k & 7;
- ZIPDUMPBITS(n);
-
- /* get the length and its complement */
- ZIPNEEDBITS(16)
- n = ((ULONG)b & 0xffff);
- ZIPDUMPBITS(16)
- ZIPNEEDBITS(16)
- if (n != (ULONG)((~b) & 0xffff))
- return 1; /* error in compressed data */
- ZIPDUMPBITS(16)
-
- /* read and output the compressed data */
- while(n--)
- {
- ZIPNEEDBITS(8)
- CAB(outbuf)[w++] = (UBYTE)b;
- ZIPDUMPBITS(8)
- }
-
- /* restore the globals from the locals */
- ZIP(window_posn) = w; /* restore global window pointer */
- ZIP(bb) = b; /* restore global bit buffer */
- ZIP(bk) = k;
- return 0;
- }
-
- static LONG Zipinflate_fixed(CABSTATE)
- {
- struct Ziphuft *fixed_tl;
- struct Ziphuft *fixed_td;
- LONG fixed_bl, fixed_bd;
- LONG i; /* temporary variable */
- ULONG *l;
-
- l = ZIP(ll);
-
- /* literal table */
- for(i = 0; i < 144; i++)
- l[i] = 8;
- for(; i < 256; i++)
- l[i] = 9;
- for(; i < 280; i++)
- l[i] = 7;
- for(; i < 288; i++) /* make a complete, but wrong code set */
- l[i] = 8;
- fixed_bl = 7;
- if((i = Ziphuft_build(cabstate, l, 288, 257, (UWORD *) Zipcplens, (UWORD *) Zipcplext, &fixed_tl, &fixed_bl)))
- return i;
-
- /* distance table */
- for(i = 0; i < 30; i++) /* make an incomplete code set */
- l[i] = 5;
- fixed_bd = 5;
- if((i = Ziphuft_build(cabstate, l, 30, 0, (UWORD *) Zipcpdist, (UWORD *) Zipcpdext, &fixed_td, &fixed_bd)) > 1)
- {
- Ziphuft_free(cabstate, fixed_tl);
- return i;
- }
-
- /* decompress until an end-of-block code */
- i = Zipinflate_codes(cabstate, fixed_tl, fixed_td, fixed_bl, fixed_bd);
-
- Ziphuft_free(cabstate, fixed_td);
- Ziphuft_free(cabstate, fixed_tl);
- return i;
- }
-
- static LONG Zipinflate_dynamic(CABSTATE) /* decompress an inflated type 2 (dynamic Huffman codes) block. */
- {
- LONG i; /* temporary variables */
- ULONG j;
- ULONG *ll;
- ULONG l; /* last length */
- ULONG m; /* mask for bit lengths table */
- ULONG n; /* number of lengths to get */
- struct Ziphuft *tl; /* literal/length code table */
- struct Ziphuft *td; /* distance code table */
- LONG bl; /* lookup bits for tl */
- LONG bd; /* lookup bits for td */
- ULONG nb; /* number of bit length codes */
- ULONG nl; /* number of literal/length codes */
- ULONG nd; /* number of distance codes */
- register ULONG b; /* bit buffer */
- register ULONG k; /* number of bits in bit buffer */
-
- /* make local bit buffer */
- b = ZIP(bb);
- k = ZIP(bk);
- ll = ZIP(ll);
-
- /* read in table lengths */
- ZIPNEEDBITS(5)
- nl = 257 + ((ULONG)b & 0x1f); /* number of literal/length codes */
- ZIPDUMPBITS(5)
- ZIPNEEDBITS(5)
- nd = 1 + ((ULONG)b & 0x1f); /* number of distance codes */
- ZIPDUMPBITS(5)
- ZIPNEEDBITS(4)
- nb = 4 + ((ULONG)b & 0xf); /* number of bit length codes */
- ZIPDUMPBITS(4)
- if(nl > 288 || nd > 32)
- return 1; /* bad lengths */
-
- /* read in bit-length-code lengths */
- for(j = 0; j < nb; j++)
- {
- ZIPNEEDBITS(3)
- ll[Zipborder[j]] = (ULONG)b & 7;
- ZIPDUMPBITS(3)
- }
- for(; j < 19; j++)
- ll[Zipborder[j]] = 0;
-
- /* build decoding table for trees--single level, 7 bit lookup */
- bl = 7;
- if((i = Ziphuft_build(cabstate, ll, 19, 19, NULL, NULL, &tl, &bl)) != 0)
- {
- if(i == 1)
- Ziphuft_free(cabstate, tl);
- return i; /* incomplete code set */
- }
-
- /* read in literal and distance code lengths */
- n = nl + nd;
- m = Zipmask[bl];
- i = l = 0;
- while((ULONG)i < n)
- {
- ZIPNEEDBITS((ULONG)bl)
- j = (td = tl + ((ULONG)b & m))->b;
- ZIPDUMPBITS(j)
- j = td->v.n;
- if (j < 16) /* length of code in bits (0..15) */
- ll[i++] = l = j; /* save last length in l */
- else if (j == 16) /* repeat last length 3 to 6 times */
- {
- ZIPNEEDBITS(2)
- j = 3 + ((ULONG)b & 3);
- ZIPDUMPBITS(2)
- if((ULONG)i + j > n)
- return 1;
- while (j--)
- ll[i++] = l;
- }
- else if (j == 17) /* 3 to 10 zero length codes */
- {
- ZIPNEEDBITS(3)
- j = 3 + ((ULONG)b & 7);
- ZIPDUMPBITS(3)
- if ((ULONG)i + j > n)
- return 1;
- while (j--)
- ll[i++] = 0;
- l = 0;
- }
- else /* j == 18: 11 to 138 zero length codes */
- {
- ZIPNEEDBITS(7)
- j = 11 + ((ULONG)b & 0x7f);
- ZIPDUMPBITS(7)
- if ((ULONG)i + j > n)
- return 1;
- while (j--)
- ll[i++] = 0;
- l = 0;
- }
- }
-
- /* free decoding table for trees */
- Ziphuft_free(cabstate, tl);
-
- /* restore the global bit buffer */
- ZIP(bb) = b;
- ZIP(bk) = k;
-
- /* build the decoding tables for literal/length and distance codes */
- bl = ZIPLBITS;
- if((i = Ziphuft_build(cabstate, ll, nl, 257, (UWORD *) Zipcplens, (UWORD *) Zipcplext, &tl, &bl)) != 0)
- {
- if(i == 1)
- Ziphuft_free(cabstate, tl);
- return i; /* incomplete code set */
- }
- bd = ZIPDBITS;
- Ziphuft_build(cabstate, ll + nl, nd, 0, (UWORD *) Zipcpdist, (UWORD *) Zipcpdext, &td, &bd);
-
- /* decompress until an end-of-block code */
- if(Zipinflate_codes(cabstate, tl, td, bl, bd))
- return 1;
-
- /* free the decoding tables, return */
- Ziphuft_free(cabstate, tl);
- Ziphuft_free(cabstate, td);
- return 0;
- }
-
- static LONG Zipinflate_block(CABSTATE, LONG *e) /* e == last block flag */
- { /* decompress an inflated block */
- ULONG t; /* block type */
- register ULONG b; /* bit buffer */
- register ULONG k; /* number of bits in bit buffer */
-
- /* make local bit buffer */
- b = ZIP(bb);
- k = ZIP(bk);
-
- /* read in last block bit */
- ZIPNEEDBITS(1)
- *e = (LONG)b & 1;
- ZIPDUMPBITS(1)
-
- /* read in block type */
- ZIPNEEDBITS(2)
- t = (ULONG)b & 3;
- ZIPDUMPBITS(2)
-
- /* restore the global bit buffer */
- ZIP(bb) = b;
- ZIP(bk) = k;
-
- D(("ZIP: blocktype=%ld, last block=%ld\n", t, *e))
-
- /* inflate that block type */
- if(t == 2)
- return Zipinflate_dynamic(cabstate);
- if(t == 0)
- return Zipinflate_stored(cabstate);
- if(t == 1)
- return Zipinflate_fixed(cabstate);
- /* bad block type */
- return 2;
- }
-
- LONG CAB_ZIPdecompress(CABSTATE, int inlen, int outlen)
- {
- LONG e; /* last block flag */
-
- D(("ZIP: outlen %ld\n", outlen))
- ZIP(inpos) = CAB(inbuf);
- ZIP(bb) = ZIP(bk) = ZIP(window_posn) = 0;
- if(outlen > ZIPWSIZE)
- return XADERR_DATAFORMAT;
-
- /* CK = Chris Kirmse, official Microsoft purloiner */
- if(ZIP(inpos)[0] != 0x43 || ZIP(inpos)[1] != 0x4B)
- return XADERR_ILLEGALDATA;
- ZIP(inpos) += 2;
-
- do
- {
- if(Zipinflate_block(cabstate, &e))
- return XADERR_ILLEGALDATA;
- } while(!e);
-
- /* return success */
- return XADERR_OK;
- }
-
- /*--------------------------------------------------------------------------*/
- /* Quantum decompressor */
-
- LONG CAB_QTMinit(CABSTATE, int level, int window) {
- struct xadMasterBase *xadMasterBase = CAB(xad);
- ULONG wndsize = 1 << window;
-
- /* Quantum supports window sizes of 2^10 (4Kb) through 2^21 (2Mb) */
- /* if a previously allocated window is big enough, keep it */
- if (window < 10 || window > 21) return XADERR_DATAFORMAT;
- if (QTM(actual_size) < wndsize) {
- if (QTM(window)) FREE(QTM(window));
- QTM(window) = NULL;
- }
- if (!QTM(window)) {
- /* not using ALLOC() macro because we don't need to clear the window */
- if (!(QTM(window) = xadAllocVec(wndsize, 0))) return XADERR_NOMEMORY;
- QTM(actual_size) = wndsize;
- }
- QTM(window_size) = wndsize;
- QTM(comp_level) = level;
-
- return XADERR_OK;
- }
-
- void CAB_QTMfree(CABSTATE) {
- struct xadMasterBase *xadMasterBase = CAB(xad);
- if (QTM(window)) FREE(QTM(window));
- QTM(window) = NULL;
- }
-
-
- LONG CAB_QTMdecompress(CABSTATE, int inlen, int outlen) {
- return XADERR_DATAFORMAT;
- }
-
- /*--------------------------------------------------------------------------*/
- /* LZX decompressor */
-
- /* Microsoft's LZX document and their implementation of the
- * com.ms.util.cab Java package do not concur.
- *
- * Correlation between window size and number of position slots: In the
- * LZX document, 1MB window = 40 slots, 2MB window = 42 slots. In the
- * implementation, 1MB = 42 slots, 2MB = 50 slots. (The actual calculation
- * is 'find the first slot whose position base is equal to or more than the
- * required window size'). This would explain why other tables in the
- * document refer to 50 slots rather than 42.
- *
- * The constant NUM_PRIMARY_LENGTHS used in the decompression pseudocode
- * is not defined in the specification, although it could be derived from
- * the section on encoding match lengths.
- *
- * The LZX document does not state the uncompressed block has an
- * uncompressed length. Where does this length field come from, so we can
- * know how large the block is? The implementation suggests that it's in
- * the 24 bits proceeding the 3 blocktype bits, before the alignment
- * padding.
- *
- * The LZX document states that aligned offset blocks have their aligned
- * offset huffman tree AFTER the main and length tree. The implementation
- * suggests that the aligned offset tree is BEFORE the main and length trees.
- *
- * The LZX document decoding algorithim states that, in an aligned offset
- * block, if an extra_bits value is 1, 2 or 3, then that number of bits
- * should be read and the result added to the match offset. This is correct
- * for 1 and 2, but not 3 bits, where only an aligned symbol should be read.
- */
-
- /* LZX uses what it calls 'position slots' to represent match offsets.
- * What this means is that a small 'position slot' number and a small
- * offset from that slot are encoded instead of one large offset for
- * every match.
- * - position_base is an index to the position slot bases
- * - extra_bits states how many bits of offset-from-base data is needed.
- */
- static ULONG position_base[51];
- static UBYTE extra_bits[51];
-
-
- LONG CAB_LZXinit(CABSTATE, int window) {
- struct xadMasterBase *xadMasterBase = CAB(xad);
- int wndsize = 1 << window;
- int i, j, posn_slots;
-
- D(("LZX: init wndsize=%ld\n", window))
-
- /* LZX supports window sizes of 2^15 (32Kb) through 2^21 (2Mb) */
- /* if a previously allocated window is big enough, keep it */
- if (window < 15 || window > 21) return XADERR_DATAFORMAT;
- if (LZX(actual_size) < wndsize) {
- if (LZX(window)) FREE(LZX(window));
- LZX(window) = NULL;
- }
- if (!LZX(window)) {
- /* not using ALLOC() macro because we don't need to clear the window */
- if (!(LZX(window) = xadAllocVec(wndsize, 0))) return XADERR_NOMEMORY;
- LZX(actual_size) = wndsize;
- }
- LZX(window_size) = wndsize;
-
- /* initialise static tables */
- for (i=0, j=0; i <= 50; i += 2) {
- extra_bits[i] = extra_bits[i+1] = j; /* 0,0,0,0,1,1,2,2,3,3... */
- if ((i != 0) && (j < 17)) j++; /* 0,0,1,2,3,4...15,16,17,17,17,17... */
- }
- for (i=0, j=0; i <= 50; i++) {
- position_base[i] = j; /* 0,1,2,3,4,6,8,12,16,24,32,... */
- j += 1 << extra_bits[i]; /* 1,1,1,1,2,2,4,4,8,8,16,16,32,32,... */
- }
-
- /* calculate required position slots */
- if (window == 20) posn_slots = 42;
- else if (window == 21) posn_slots = 50;
- else posn_slots = window << 1;
-
- /*posn_slots=i=0; while (i < wndsize) i += 1 << extra_bits[posn_slots++]; */
-
-
- LZX(R0) = LZX(R1) = LZX(R2) = 1;
- LZX(main_elements) = LZX_NUM_CHARS + (posn_slots << 3);
- LZX(header_read) = 0;
- LZX(frames_read) = 0;
- LZX(block_remaining) = 0;
- LZX(block_type) = LZX_BLOCKTYPE_INVALID;
- LZX(intel_curpos) = 0;
- LZX(intel_started) = 0;
- LZX(window_posn) = 0;
-
- /* initialise tables to 0 (because deltas will be applied to them) */
- for (i = 0; i < LZX_MAINTREE_MAXSYMBOLS; i++) LZX(MAINTREE_len)[i] = 0;
- for (i = 0; i < LZX_LENGTH_MAXSYMBOLS; i++) LZX(LENGTH_len)[i] = 0;
-
- return XADERR_OK;
- }
-
- void CAB_LZXfree(CABSTATE) {
- struct xadMasterBase *xadMasterBase = CAB(xad);
- if (LZX(window)) FREE(LZX(window));
- LZX(window) = NULL;
- }
-
-
-
- /* Bitstream reading macros:
- *
- * INIT_BITSTREAM should be used first to set up the system
- * READ_BITS(var,n) takes N bits from the buffer and puts them in var
- *
- * ENSURE_BITS(n) ensures there are at least N bits in the bit buffer
- * PEEK_BITS(n) extracts (without removing) N bits from the bit buffer
- * REMOVE_BITS(n) removes N bits from the bit buffer
- *
- * These bit access routines work by using the area beyond the MSB and the
- * LSB as a free source of zeroes. This avoids having to mask any bits.
- * So we have to know the bit width of the bitbuffer variable. This is
- * sizeof(ULONG) * 8, also defined as ULONG_BITS
- */
-
- /* number of bits in ULONG. Note: This must be at multiple of 16, and at
- * least 32 for the bitbuffer code to work (ie, it must be able to ensure
- * up to 17 bits - that's adding 16 bits when there's one bit left, or
- * adding 32 bits when there are no bits left. The code should work fine
- * for machines where ULONG >= 32 bits.
- */
- #define ULONG_BITS (sizeof(ULONG)<<3)
-
- #define INIT_BITSTREAM do { bitsleft = 0; bitbuf = 0; } while (0)
-
- #define ENSURE_BITS(n) \
- while (bitsleft < (n)) { \
- bitbuf |= ((inpos[1]<<8)|inpos[0]) << (ULONG_BITS-16 - bitsleft); \
- bitsleft += 16; inpos+=2; \
- }
-
- #define PEEK_BITS(n) (bitbuf >> (ULONG_BITS - (n)))
- #define REMOVE_BITS(n) ((bitbuf <<= (n)), (bitsleft -= (n)))
-
- #define READ_BITS(v,n) do { \
- ENSURE_BITS(n); \
- (v) = PEEK_BITS(n); \
- REMOVE_BITS(n); \
- /*D(("getbits(%ld)=%ld\n",n,(v)))*/ \
- } while (0)
-
-
- /* Huffman macros */
-
- #define TABLEBITS(tbl) (LZX_##tbl##_TABLEBITS)
- #define MAXSYMBOLS(tbl) (LZX_##tbl##_MAXSYMBOLS)
- #define SYMTABLE(tbl) (LZX(tbl##_table))
- #define LENTABLE(tbl) (LZX(tbl##_len))
-
- /* BUILD_TABLE(tablename) builds a huffman lookup table from code lengths.
- * In reality, it just calls make_decode_table() with the appropriate
- * values - they're all fixed by some #defines anyway, so there's no point
- * writing each call out in full by hand.
- */
- #define BUILD_TABLE(tbl) \
- if (make_decode_table( \
- MAXSYMBOLS(tbl), TABLEBITS(tbl), LENTABLE(tbl), SYMTABLE(tbl) \
- )) { D(("LZX: table failure\n")) return XADERR_ILLEGALDATA; }
-
-
- /* READ_HUFFSYM(tablename, var) decodes one huffman symbol from the
- * bitstream using the stated table and puts it in var.
- */
- #define READ_HUFFSYM(tbl,var) do { \
- ENSURE_BITS(16); \
- hufftbl = SYMTABLE(tbl); \
- if ((i = hufftbl[PEEK_BITS(TABLEBITS(tbl))]) >= MAXSYMBOLS(tbl)) { \
- j = 1 << (ULONG_BITS - TABLEBITS(tbl)); \
- do { \
- j >>= 1; i <<= 1; i |= (bitbuf & j) ? 1 : 0; \
- if (!j) return XADERR_ILLEGALDATA; \
- } while ((i = hufftbl[i]) >= MAXSYMBOLS(tbl)); \
- } \
- j = LENTABLE(tbl)[(var) = i]; \
- REMOVE_BITS(j); \
- } while (0)
-
-
- /* READ_LENGTHS(tablename, first, last) reads in code lengths for symbols
- * first to last in the given table. The code lengths are stored in their
- * own special LZX way. Note that we pass in an lzx_bits structure to
- * get the bitstream state between the function and the caller - this has
- * to be initialised before using READ_LENGTHS, and retrieved again before
- * the bit macros are next used.
- */
- #define READ_LENGTHS(tbl,first,last) \
- if (lzx_read_lens(cabstate, LENTABLE(tbl), (first), (last), &lb)) \
- return XADERR_ILLEGALDATA;
-
- struct lzx_bits {
- ULONG bb;
- int bl;
- UBYTE *ip;
- };
-
-
- /* make_decode_table(nsyms, nbits, length[], table[])
- *
- * This function was coded by David Tritscher. It builds a fast huffman
- * decoding table out of just a canonical huffman code lengths table.
- *
- * nsyms = total number of symbols in this huffman tree.
- * nbits = any symbols with a code length of nbits or less can be decoded
- * in one lookup of the table.
- * length = A table to get code lengths from [0 to syms-1]
- * table = The table to fill up with decoded symbols and pointers.
- *
- * Returns 0 for OK or 1 for error
- */
- int make_decode_table(int nsyms, int nbits, UBYTE *length, UWORD *table) {
- register UWORD sym;
- register ULONG leaf;
- register UBYTE bit_num = 1;
- ULONG fill;
- ULONG pos = 0; /* the current position in the decode table */
- ULONG table_mask = 1 << nbits;
- ULONG bit_mask = table_mask >> 1; /* don't do 0 length codes */
- ULONG next_symbol = bit_mask; /* base of allocation for long codes */
-
- /* fill entries for codes short enough for a direct mapping */
- while (bit_num <= nbits) {
- for (sym = 0; sym < nsyms; sym++) {
- if (length[sym] == bit_num) {
- leaf = pos;
-
- if((pos += bit_mask) > table_mask) return 1; /* table overrun */
-
- /* fill all possible lookups of this symbol with the symbol itself */
- fill = bit_mask;
- while (fill-- > 0) table[leaf++] = sym;
- }
- }
- bit_mask >>= 1;
- bit_num++;
- }
-
- /* if there are any codes longer than nbits */
- if (pos != table_mask) {
- /* clear the remainder of the table */
- for (sym = pos; sym < table_mask; sym++) table[sym] = 0;
-
- /* give ourselves room for codes to grow by up to 16 more bits */
- pos <<= 16;
- table_mask <<= 16;
- bit_mask = 1 << 15;
-
- while (bit_num <= 16) {
- for (sym = 0; sym < nsyms; sym++) {
- if (length[sym] == bit_num) {
- leaf = pos >> 16;
- for (fill = 0; fill < bit_num - nbits; fill++) {
- /* if this path hasn't been taken yet, 'allocate' two entries */
- if (table[leaf] == 0) {
- table[(next_symbol << 1)] = 0;
- table[(next_symbol << 1) + 1] = 0;
- table[leaf] = next_symbol++;
- }
- /* follow the path and select either left or right for next bit */
- leaf = table[leaf] << 1;
- if ((pos >> (15-fill)) & 1) leaf++;
- }
- table[leaf] = sym;
-
- if ((pos += bit_mask) > table_mask) return 1; /* table overflow */
- }
- }
- bit_mask >>= 1;
- bit_num++;
- }
- }
-
- /* full table? */
- if (pos == table_mask) return 0;
-
- /* either erroneous table, or all elements are 0 - let's find out. */
- for (sym = 0; sym < nsyms; sym++) if (length[sym]) return 1;
- return 0;
- }
-
-
- int lzx_read_lens(CABSTATE, UBYTE *lens, int f, int l, struct lzx_bits *lb) {
- ULONG i,j, x,y;
- int z;
-
- register ULONG bitbuf = lb->bb;
- register int bitsleft = lb->bl;
- UBYTE *inpos = lb->ip;
- UWORD *hufftbl;
-
- for (x = 0; x < 20; x++) {
- READ_BITS(y, 4);
- LENTABLE(PRETREE)[x] = y;
- }
- BUILD_TABLE(PRETREE);
-
- for (x = f; x < l; ) {
- READ_HUFFSYM(PRETREE, z);
-
- if (z == 17) {
- READ_BITS(y, 4); y += 4;
- while (y--) lens[x++] = 0;
- }
- else if (z == 18) {
- READ_BITS(y, 5); y += 20;
- while (y--) lens[x++] = 0;
- }
- else if (z == 19) {
- READ_BITS(y, 1); y += 4;
- READ_HUFFSYM(PRETREE, z);
- z = lens[x] - z; if (z < 0) z += 17;
- while (y--) lens[x++] = z;
- }
- else {
- z = lens[x] - z; if (z < 0) z += 17;
- lens[x++] = z;
- }
- }
-
- lb->bb = bitbuf;
- lb->bl = bitsleft;
- lb->ip = inpos;
-
- /*for (x = f; x < l; x++) D(("length[%ld]=%ld\n", x, lens[x]))*/
-
- return 0;
- }
-
-
- LONG CAB_LZXdecompress(CABSTATE, int inlen, int outlen) {
- struct xadMasterBase *xadMasterBase = CAB(xad);
- UBYTE *inpos = CAB(inbuf);
- UBYTE *endinp = inpos + inlen;
- UBYTE *window = LZX(window);
- UBYTE *runsrc, *rundest;
- UWORD *hufftbl; /* used in READ_HUFFSYM macro as chosen decoding table */
-
- ULONG window_posn = LZX(window_posn);
- ULONG window_size = LZX(window_size);
- ULONG R0 = LZX(R0);
- ULONG R1 = LZX(R1);
- ULONG R2 = LZX(R2);
-
- register ULONG bitbuf;
- register int bitsleft;
- ULONG match_offset, i,j,k; /* ijk used in READ_HUFFSYM macro */
- struct lzx_bits lb; /* used in READ_LENGTHS macro */
-
- int togo = outlen, this_run, main_element, aligned_bits;
- int match_length, length_footer, extra, verbatim_bits;
-
- INIT_BITSTREAM;
-
- /* read header if necessary */
- if (!LZX(header_read)) {
- i = j = 0;
- READ_BITS(k, 1); if (k) { READ_BITS(i,16); READ_BITS(j,16); }
- LZX(intel_filesize) = (i << 16) | j; /* or 0 if not encoded */
- LZX(header_read) = 1;
- }
-
- /* main decoding loop */
- while (togo > 0) {
- D(("LZX: top of loop, %ld togo\n", togo))
-
- /* last block finished, new block expected */
- if (LZX(block_remaining) == 0) {
- if (LZX(block_type) == LZX_BLOCKTYPE_UNCOMPRESSED) {
- if (LZX(block_length) & 1) inpos++; /* realign bitstream to word */
- INIT_BITSTREAM;
- D(("LZX: aligning after previous uncompressed block\n"))
- }
-
- READ_BITS(LZX(block_type), 3);
- READ_BITS(i, 16);
- READ_BITS(j, 8);
- LZX(block_remaining) = LZX(block_length) = (i << 8) | j;
-
- D(("LZX: new %ld block len=%ld\n", LZX(block_type), LZX(block_length)))
-
- switch (LZX(block_type)) {
- case LZX_BLOCKTYPE_ALIGNED:
- for (i = 0; i < 8; i++) { READ_BITS(j, 3); LENTABLE(ALIGNED)[i] = j; }
- BUILD_TABLE(ALIGNED);
- /* rest of aligned header is same as verbatim */
-
- case LZX_BLOCKTYPE_VERBATIM:
- /* set up a pass-in structure with bitstream state for READ_LENGTHS */
- lb.bb = bitbuf; lb.bl = bitsleft; lb.ip = inpos;
-
- READ_LENGTHS(MAINTREE, 0, 256);
- READ_LENGTHS(MAINTREE, 256, LZX(main_elements));
- BUILD_TABLE(MAINTREE);
- if (LENTABLE(MAINTREE)[0xE8] != 0) LZX(intel_started) = 1;
-
- READ_LENGTHS(LENGTH, 0, LZX_NUM_SECONDARY_LENGTHS);
- BUILD_TABLE(LENGTH);
-
- /* retrieve the bitstream state from the readlens structure */
- bitbuf = lb.bb; bitsleft = lb.bl; inpos = lb.ip;
-
- break;
-
- case LZX_BLOCKTYPE_UNCOMPRESSED:
- LZX(intel_started) = 1; /* because we can't assume otherwise */
- ENSURE_BITS(16); /* get up to 16 pad bits into the buffer */
- if (bitsleft > 16) inpos -= 2; /* and align the bitstream! */
- LZX(R0)=inpos[0]|(inpos[1]<<8)|(inpos[2]<<16)|(inpos[3]<<24);inpos+=4;
- LZX(R1)=inpos[0]|(inpos[1]<<8)|(inpos[2]<<16)|(inpos[3]<<24);inpos+=4;
- LZX(R2)=inpos[0]|(inpos[1]<<8)|(inpos[2]<<16)|(inpos[3]<<24);inpos+=4;
- D(("LZX: uncomp header; Rx=%ld/%ld/%ld\n",LZX(R0),LZX(R1),LZX(R2)))
- break;
-
- default:
- return XADERR_ILLEGALDATA;
- }
- D(("LZX: block header read OK\n"))
- }
-
- if (inpos > endinp) return XADERR_ILLEGALDATA;
-
- while ((this_run = LZX(block_remaining)) > 0 && togo > 0) {
- D(("LZX: block remaining = %ld, togo = %ld\n", this_run, togo))
- if (this_run > togo) this_run = togo;
- togo -= this_run;
- LZX(block_remaining) -= this_run;
-
- /* apply 2^x-1 mask */
- window_posn &= window_size - 1;
- /* runs can't straddle the window wraparound */
- if ((window_posn + this_run) > window_size)
- return XADERR_DATAFORMAT;
-
- switch (LZX(block_type)) {
-
- case LZX_BLOCKTYPE_VERBATIM:
- while (this_run > 0) {
- READ_HUFFSYM(MAINTREE, main_element);
- /*D(("%ld\n",main_element))*/
- if (main_element < LZX_NUM_CHARS) {
- /* literal: 0 to LZX_NUM_CHARS-1 */
- window[window_posn++] = main_element;
- this_run--;
- }
- else {
- /* match: LZX_NUM_CHARS + ((slot<<3) | length_header (3 bits)) */
- main_element -= LZX_NUM_CHARS;
-
- match_length = main_element & LZX_NUM_PRIMARY_LENGTHS;
- if (match_length == LZX_NUM_PRIMARY_LENGTHS) {
- READ_HUFFSYM(LENGTH, length_footer);
- match_length += length_footer;
- }
- match_length += LZX_MIN_MATCH;
-
- match_offset = main_element >> 3;
-
- if (match_offset > 2) {
- /* not repeated offset */
- if (match_offset != 3) {
- extra = extra_bits[match_offset];
- READ_BITS(verbatim_bits, extra);
- match_offset = position_base[match_offset] - 2 + verbatim_bits;
- }
- else {
- match_offset = 1;
- }
-
- /* update repeated offset LRU queue */
- R2 = R1; R1 = R0; R0 = match_offset;
- }
- else if (match_offset == 0) {
- match_offset = R0;
- }
- else if (match_offset == 1) {
- match_offset = R1;
- R1 = R0; R0 = match_offset;
- }
- else /* match_offset == 2 */ {
- match_offset = R2;
- R2 = R0; R0 = match_offset;
- }
-
- /*D(("%ld,%ld\n",match_length,match_offset))*/
- rundest = window + window_posn;
- runsrc = rundest - match_offset;
- window_posn += match_length;
- this_run -= match_length;
-
- /* copy any wrapped around source data */
- while ((runsrc < window) && (match_length-- > 0)) {
- *rundest++ = *(runsrc + window_size); runsrc++;
- }
- /* copy match data - no worries about destination wraps */
- while (match_length-- > 0) *rundest++ = *runsrc++;
-
- }
- }
- break;
-
- case LZX_BLOCKTYPE_ALIGNED:
- while (this_run > 0) {
- READ_HUFFSYM(MAINTREE, main_element);
- /*D(("%ld\n",main_element))*/
-
- if (main_element < LZX_NUM_CHARS) {
- /* literal: 0 to LZX_NUM_CHARS-1 */
- window[window_posn++] = main_element;
- this_run--;
- }
- else {
- /* match: LZX_NUM_CHARS + ((slot<<3) | length_header (3 bits)) */
- main_element -= LZX_NUM_CHARS;
-
- match_length = main_element & LZX_NUM_PRIMARY_LENGTHS;
- if (match_length == LZX_NUM_PRIMARY_LENGTHS) {
- READ_HUFFSYM(LENGTH, length_footer);
- match_length += length_footer;
- }
- match_length += LZX_MIN_MATCH;
-
- match_offset = main_element >> 3;
-
- if (match_offset > 2) {
- /* not repeated offset */
- extra = extra_bits[match_offset];
- match_offset = position_base[match_offset] - 2;
- if (extra > 3) {
- /* verbatim and aligned bits */
- extra -= 3;
- READ_BITS(verbatim_bits, extra);
- match_offset += (verbatim_bits << 3);
- READ_HUFFSYM(ALIGNED, aligned_bits);
- match_offset += aligned_bits;
- }
- else if (extra == 3) {
- /* aligned bits only */
- READ_HUFFSYM(ALIGNED, aligned_bits);
- match_offset += aligned_bits;
- }
- else if (extra > 0) { /* extra==1, extra==2 */
- /* verbatim bits only */
- READ_BITS(verbatim_bits, extra);
- match_offset += verbatim_bits;
- }
- else /* extra == 0 */ {
- /* ??? */
- match_offset = 1;
- }
-
- /* update repeated offset LRU queue */
- R2 = R1; R1 = R0; R0 = match_offset;
- }
- else if (match_offset == 0) {
- match_offset = R0;
- }
- else if (match_offset == 1) {
- match_offset = R1;
- R1 = R0; R0 = match_offset;
- }
- else /* match_offset == 2 */ {
- match_offset = R2;
- R2 = R0; R0 = match_offset;
- }
-
- /*D(("%ld,%ld\n",match_length,match_offset))*/
- rundest = window + window_posn;
- runsrc = rundest - match_offset;
- window_posn += match_length;
- this_run -= match_length;
-
- /* copy any wrapped around source data */
- while ((runsrc < window) && (match_length-- > 0)) {
- *rundest++ = *(runsrc + window_size); runsrc++;
- }
- /* copy match data - no worries about destination wraps */
- while (match_length-- > 0) *rundest++ = *runsrc++;
-
- }
- }
- break;
-
- case LZX_BLOCKTYPE_UNCOMPRESSED:
- if ((inpos + this_run) > endinp) return XADERR_ILLEGALDATA;
- xadCopyMem(inpos, window + window_posn, this_run);
- inpos += this_run; window_posn += this_run;
- break;
-
- default:
- return XADERR_ILLEGALDATA; /* might as well */
- }
-
- }
- }
-
- if (togo != 0) return XADERR_ILLEGALDATA;
- xadCopyMem(window + ((window_posn == 0) ? window_size : window_posn) -
- outlen, CAB(outbuf), outlen);
-
- LZX(window_posn) = window_posn;
- LZX(R0) = R0;
- LZX(R1) = R1;
- LZX(R2) = R2;
-
- /* intel decoding */
- if ((LZX(frames_read)++ < 32768) && LZX(intel_filesize) != 0) {
- if (outlen <= 6 || !LZX(intel_started)) {
- LZX(intel_curpos) += outlen;
- }
- else {
- UBYTE *data = CAB(outbuf);
- UBYTE *dataend = data + outlen - 6;
- LONG curpos = LZX(intel_curpos);
- LONG filesize = LZX(intel_filesize);
- LONG abs_off, rel_off;
-
- LZX(intel_curpos) = curpos + outlen;
-
- while (data < dataend) {
- if (*data++ != 0xE8) { curpos++; continue; }
- abs_off = data[0] | (data[1]<<8) | (data[2]<<16) | (data[3]<<24);
- if ((abs_off >= -curpos) && (abs_off < filesize)) {
- rel_off = (abs_off >= 0) ? abs_off - curpos : abs_off + filesize;
- data[0] = (UBYTE) rel_off;
- data[1] = (UBYTE) (rel_off >> 8);
- data[2] = (UBYTE) (rel_off >> 16);
- data[3] = (UBYTE) (rel_off >> 24);
- /*D(("LZX: E8 abs=%08lx rel=%08lx\n",abs_off,rel_off))*/
- }
- data += 4;
- curpos += 5;
- }
- }
- }
- return XADERR_OK;
- }
-
-
- /*--------------------------------------------------------------------------*/
- /* CAB RecogData/GetInfo code */
-
- /* UTF translates two-byte unicode characters into 1, 2 or 3 bytes.
- * %000000000xxxxxxx (0x0000 - 0x007F) -> %0xxxxxxx
- * %00000xxxxxyyyyyy (0x0080 - 0x07FF) -> %110xxxxx %10yyyyyy
- * %xxxxyyyyyyzzzzzz (0x0800 - 0xFFFF) -> %1110xxxx %10yyyyyy %10zzzzzz
- *
- * Therefore, the inverse is as follows:
- * First char:
- * 0x00 - 0x7F = one byte char
- * 0x80 - 0xBF = invalid
- * 0xC0 - 0xDF = 2 byte char (next char only 0x80-0xBF is valid)
- * 0xE0 - 0xEF = 3 byte char (next 2 chars only 0x80-0xBF is valid)
- * 0xF0 - 0xFF = invalid
- */
- /* translates a UTF string into an ISO latin1 string, returns success */
- int CAB_convertUTF(unsigned char *in) {
- unsigned char c, *out = in, *end = in + strlen(in) + 1;
- unsigned int x;
-
- do {
- /* read unicode character */
- if ((c = *in++) < 0x80) x = c;
- else {
- if (c < 0xC0) return 0;
- else if (c < 0xE0) {
- x = (c & 0x1F) << 6;
- if ((c = *in++) < 0x80 || c > 0xBF) return 0; else x |= (c & 0x3F);
- }
- else if (c < 0xF0) {
- x = (c & 0xF) << 12;
- if ((c = *in++) < 0x80 || c > 0xBF) return 0; else x |= (c & 0x3F)<<6;
- if ((c = *in++) < 0x80 || c > 0xBF) return 0; else x |= (c & 0x3F);
- }
- else return 0;
- }
-
- /* terrible unicode -> ISO latin1 conversion */
- if (x > 255) x = '_';
-
- if (in > end) return 0; /* just in case */
- } while (*out++ = (unsigned char) x);
- return 1;
- }
-
- static const STRPTR CAB_typenames[] = {
- "stored", "MSZIP", "Quantum", "LZX"
- };
-
- ASM(BOOL) CAB_RecogData(REG(d0, ULONG size), REG(a0, STRPTR d), XADBASE) {
- return (BOOL) ((d[0]=='M' && d[1]=='S' && d[2]=='C' && d[3]=='F') ? 1 : 0);
- }
-
- ASM(LONG) SAVEDS CAB_GetInfo(REG(a0, struct xadArchiveInfo *ai), XADBASE) {
- UBYTE buf[cfhead_SIZEOF]; /* buffer for reading in structures */
- UBYTE namebuf[CAB_NAMEMAX]; /* buffer for file paths */
- UBYTE *namep, c; /* for char loops on namebuf */
-
- ULONG base_offset; /* the file offset of the start of this cabinet */
- ULONG files_offset; /* the file offset of the first CFFILE in this cabinet */
- ULONG end_offset; /* the file offset of the end of this cabinet */
-
- UWORD num_folders; /* the number of CFFOLDERs in this cabinet */
- UWORD num_files; /* the number of CFFILEs in this cabinet */
-
- UWORD header_res; /* the empty space reserved in the CFHEADER */
- UBYTE folder_res; /* the empty space reserved in each CFFOLDER */
- UBYTE data_res; /* the empty space reserved in CFDATA */
-
- int i, x, curfile=1, curvol=-1, mergeok;
-
- struct CABfolder *firstfol; /* first folder in this cabinet */
- struct CABfolder *lastfol = NULL; /* last folder in this cabinet */
- struct CABfolder *predfol; /* last folder in previous cabinet */
-
- struct CABfolder *linkfol = NULL, *fol; /* folder addition loop */
- struct xadFileInfo *link = NULL, *fi; /* file addition loop */
-
- LONG err = XADERR_OK;
-
- struct TagItem filetags[] = {
- { XAD_OBJNAMESIZE, 0 },
- { TAG_DONE, 0 }
- };
-
- struct TagItem datetags[] = {
- { XAD_DATEMSDOS, 0 },
- { XAD_GETDATEXADDATE, 0 },
- { TAG_DONE, 0 }
- };
-
- struct TagItem prottags[] = {
- { XAD_PROTMSDOS, 0 },
- { XAD_GETPROTAMIGA, 0 },
- { TAG_DONE, 0 }
- };
-
- /* attach state information to archive */
- ALLOC(APTR, ai->xai_PrivateClient, sizeof(struct CABstate));
-
- while (1) {
- /* the below if statement is the natural exit point of this loop */
- if (ai->xai_MultiVolume) {
- ULONG pos = ai->xai_InPos, next = ai->xai_MultiVolume[++curvol];
- D(("CAB: top wanted=%ld actual=%ld\n",next,pos))
- /* files end when the 'next file' offset is 0 - except, of course
- * for the very first iteration of this loop, because the first
- * file's offset is also 0
- */
- if (!next && curvol) goto exit_handler; /* end of files */
- if (pos < next) SKIP(next - pos); /* skip to next file */
- if (pos > next) ERROR(ILLEGALDATA); /* overrun error */
- }
- else {
- /* singlefile exit point - we shouldn't do more than one loop. */
- if (++curvol) goto exit_handler;
- }
-
- base_offset = ai->xai_InPos;
-
- /* ------------- PROCESS CFHEADER -------------- */
-
- READ(&buf, cfhead_SIZEOF);
- files_offset = GETLONG(cfhead_FileOffset) + base_offset;
- end_offset = GETLONG(cfhead_CabinetSize) + base_offset;
-
- if ((buf[0]!='M' || buf[1]!='S' || buf[2]!='C' || buf[3]!='F')
- || ((num_folders = GETWORD(cfhead_NumFolders)) == 0)
- || ((num_files = GETWORD(cfhead_NumFiles)) == 0))
- ERROR(ILLEGALDATA);
-
- if (GETBYTE(cfhead_MajorVersion) > 1
- || GETBYTE(cfhead_MinorVersion) > 3) ERROR(DATAFORMAT);
-
- /* read 'reserve' part of header if present and skip reserved header */
- if ((x = GETWORD(cfhead_Flags)) & cfheadRESERVE_PRESENT) {
- READ(&buf, cfheadext_SIZEOF);
- header_res = GETWORD(cfheadext_HeaderReserved);
- folder_res = GETBYTE(cfheadext_FolderReserved);
- data_res = GETBYTE(cfheadext_DataReserved);
-
- SKIP(header_res);
- if (header_res > 60000) TAINT("header reserved > 60000");
- }
- else {
- folder_res = data_res = 0;
- }
-
- /* skip next and previous cabinet filenames/disknames if present */
- i = ((x & cfheadPREV_CABINET) ? 2:0) + ((x & cfheadNEXT_CABINET) ? 2:0);
- while (i--) {
- int len = 0;
- do { READ(&buf, 1); len++; } while (*buf);
- if (len > 256) TAINT("nameskip > 256");
- }
-
-
- /* ------------- PROCESS CFFOLDERs ------------- */
-
- firstfol = NULL;
- predfol = lastfol;
-
- for (i = 0; i < num_folders; i++) {
- READ(&buf, cffold_SIZEOF);
-
- D(("CAB: folder offset=%ld comptype=0x%lx\n",
- GETLONG(cffold_DataOffset)+base_offset, GETWORD(cffold_CompType)
- ))
-
- SKIP(folder_res);
-
- ALLOC(struct CABfolder *, fol, sizeof(struct CABfolder));
- fol->offsets[0] = GETLONG(cffold_DataOffset) + base_offset;
- fol->comp_type = GETWORD(cffold_CompType);
- fol->data_res[0] = data_res;
- fol->num_splits = 0;
-
- if (!firstfol) firstfol = fol;
- lastfol = fol;
-
- /* link folder into folders list */
- if (linkfol) linkfol->next=fol;
- else ((struct CABstate *) ai->xai_PrivateClient)->folders = fol;
- linkfol = fol;
- }
-
- /* firstfol = first folder in this cabinet */
- /* lastfol = last folder in this cabinet */
- /* predfol = last folder in previous cabinet (or NULL if first cabinet) */
-
- /* assume that this cabinet's split files are OK to merge */
- mergeok = 1;
-
- /* ------------- PROCESS CFFILEs ------------- */
- if (ai->xai_InPos != files_offset) TAINT("not at file offset");
-
- for (i = 0; i < num_files; i++) {
- READ(&buf, cffile_SIZEOF);
-
- /* read filename */
- namep = namebuf;
- do {
- if ((namep - namebuf) > CAB_NAMEMAX) ERROR(NOMEMORY);
- READ(namep, 1);
- } while (*namep++);
-
- /* convert filename */
- if ((x = GETWORD(cffile_Attribs) & cffileUTFNAME)
- && !CAB_convertUTF(namebuf)) TAINT("bad UTF name");
-
- for (namep = namebuf; c = *namep; namep++) {
- if (c == '/') *namep = '\\';
- if (c == '\\') *namep = '/';
- if (!x && c > 127) *namep = '_';
- }
-
- D(("CAB: file size=%ld offset=%ld index=0x%lx name=«%s»\n",
- GETLONG(cffile_UncompressedSize), GETLONG(cffile_FolderOffset),
- GETWORD(cffile_FolderIndex), namebuf
- ))
-
- /* file information entry */
- filetags[0].ti_Data = (x = strlen((char *) namebuf) + 1);
- ALLOCOBJ(struct xadFileInfo *, fi, XADOBJ_FILEINFO, filetags);
-
- fi->xfi_EntryNumber = curfile++;
- fi->xfi_Size = GETLONG(cffile_UncompressedSize);
- fi->xfi_DataPos = GETLONG(cffile_FolderOffset);
- xadCopyMem(namebuf, fi->xfi_FileName, x);
-
- prottags[0].ti_Data = GETWORD(cffile_Attribs);
- prottags[1].ti_Data = (ULONG) &fi->xfi_Protection;
- xadConvertProtectionA(prottags);
-
- datetags[0].ti_Data = (GETWORD(cffile_Date)<<16)|GETWORD(cffile_Time);
- datetags[1].ti_Data = (ULONG) &fi->xfi_Date;
- xadConvertDatesA(datetags);
-
- /* which folder is this file in? */
- x = GETWORD(cffile_FolderIndex);
- if (x < num_folders) {
- for (fol = firstfol; x--; fol=fol->next);
- fi->xfi_PrivateInfo = (APTR) fol;
- }
- else {
- if (ai->xai_MultiVolume) {
- /* FOLDER MERGING */
-
- if (x == cffileCONTINUED_TO_NEXT
- || x == cffileCONTINUED_PREV_AND_NEXT) {
- D(("CAB: file merge next\n"))
- /* this file is in the next cabinet, so we don't set its folder
- * as it will be repeated with the 'prev' folder in the next
- * cabinet. also, if this file is continued prev and next, it
- * can only be a single file extending a single folder beyond
- * the cabinet size limits, the next file _has_ to start in a
- * new folder. we can test that.
- */
- if (x == cffileCONTINUED_PREV_AND_NEXT) {
- if (num_folders != 1 || num_files != 1) TAINT("prev/next");
- }
-
- if (!lastfol->contfile) lastfol->contfile = fi;
- }
-
- if (x == cffileCONTINUED_FROM_PREV
- || x == cffileCONTINUED_PREV_AND_NEXT) {
- D(("CAB: file merge prev\n"))
-
- /* if these files are to be continued in yet _another_ cabinet,
- * don't merge them in just yet
- */
- if (x == cffileCONTINUED_PREV_AND_NEXT) mergeok = 0;
-
- /* only merge once per cabinet */
- if (predfol) {
- struct xadFileInfo *cfi;
-
- /* in this case, the file states that folder 0 of this cabinet
- * is actually part of the last folder in the previous cabinet.
- * if this is true, the first 'continued' file of the last
- * folder will match the first file of this folder. Also,
- * both folders will have the same compression type.
- */
- if ((cfi = predfol->contfile)
- && (cfi->xfi_DataPos == fi->xfi_DataPos)
- && (cfi->xfi_Size == fi->xfi_Size)
- && (strcmp(cfi->xfi_FileName, fi->xfi_FileName) == 0)
- && (predfol->comp_type == firstfol->comp_type)) {
-
- /* free the fileinfo kept for testing if last occurance */
- if (x == cffileCONTINUED_FROM_PREV) {
- FREE(predfol->contfile);
- predfol->contfile = NULL;
- }
-
- /* increase the number of splits */
- if ((x = ++(predfol->num_splits)) > CAB_SPLITMAX)
- ERROR(DATAFORMAT);
-
- /* copy information across from the merged folder */
- predfol->offsets[x] = firstfol->offsets[0];
- predfol->data_res[x] = firstfol->data_res[0];
- predfol->next = firstfol->next;
- predfol->contfile = firstfol->contfile;
-
- if (firstfol == lastfol) lastfol = linkfol = predfol;
-
- FREE(firstfol);
- firstfol = predfol;
- predfol = NULL; /* don't merge again within this cabinet */
-
- }
- else {
- /* if the merged folders are incompatible, certainly
- * don't list the files in them
- */
- mergeok = 0;
- }
- }
-
- /* only add split files at their final appearance
- * and only if merging was actually possible
- */
- if (mergeok) fi->xfi_PrivateInfo = (APTR) firstfol;
- }
- }
- else {
- /* not multivolume - can't do a folder merge, therefore it either
- * IS a merge but there's no next/prev cabinet (missing data),
- * or it's an out of range folder index (corrupt data)
- */
- TAINT("folder index");
- }
- }
-
- /* if there's no folder, skip this file */
- if (!fi->xfi_PrivateInfo) {
- /* but only free it if never used again */
- if (fi != lastfol->contfile) FREE(fi);
- continue;
- }
- else {
- /* use compression mode of this file's folder as entryinfo name */
- UWORD ct = CABFILEFOL(fi)->comp_type & cffoldCOMPTYPE_MASK;
- if (ct <= cffoldCOMPTYPE_LZX) fi->xfi_EntryInfo = CAB_typenames[ct];
- }
-
- /* link file into file list */
- if (link) link->xfi_Next = fi; else ai->xai_FileInfo = fi;
- link = fi;
- }
-
-
- /* Skip looking at the CFDATA blocks. Why? Well, it requires us to read
- * and skip the entire file, and the only information we get from doing
- * that is how large each folder is. Why not just use the offsets
- * between folders to define that? It's slightly less accurate - some
- * would say more accurate because it counts the block header overhead
- * - and there will be a calculation error if the folders are not
- * defined in order of data block appearance [I haven't seen any such
- * files], but overall it's much faster
- */
- for (fol = firstfol; fol; fol=fol->next) {
- fol->comp_size =
- ((fol->next) ? fol->next->offsets[0] : end_offset) - fol->offsets[0];
- }
- }
-
- exit_handler:
- /* free any continuation comparison files in use */
- fol = ((struct CABstate *) ai->xai_PrivateClient)->folders;
- for (; fol; fol=fol->next) {
- if (fol->contfile) {
- TAINT("incomplete folder merge");
- FREE(fol->contfile);
- }
- }
-
- /* fill in group crunched sizes */
- for (fi = ai->xai_FileInfo; fi; fi = fi->xfi_Next) {
- fi->xfi_Flags = XADFIF_GROUPED;
- if (!fi->xfi_Next || (CABFILEFOL(fi) != CABFILEFOL(fi->xfi_Next))) {
- fi->xfi_Flags |= XADFIF_ENDOFGROUP;
- fi->xfi_GroupCrSize = CABFILEFOL(fi)->comp_size;
- }
- }
-
- /* if tainted, add the tainted lasterror */
- if (ai->xai_Flags & XADAIF_FILECORRUPT)
- ai->xai_LastError = XADERR_ILLEGALDATA;
-
- /* if a real error, then if we have files, taint and set, otherwise quit */
- if (err) {
- if (!ai->xai_FileInfo) return err;
- ai->xai_Flags |= XADAIF_FILECORRUPT;
- ai->xai_LastError = err;
- D(("CAB: info error=%ld\n", err))
- }
- return XADERR_OK;
- }
-
-
-
- /*--------------------------------------------------------------------------*/
- /* UnArchive / Free section */
-
- LONG CAB_NONEdecompress(CABSTATE, int inlen, int outlen) {
- struct xadMasterBase *xadMasterBase = CAB(xad);
-
- if (inlen != outlen) return XADERR_ILLEGALDATA;
- xadCopyMem(CAB(inbuf), CAB(outbuf), inlen);
- return XADERR_OK;
- }
-
- ULONG CAB_checksum(UBYTE *data, UWORD bytes, ULONG csum) {
- int len;
- ULONG ul = 0;
-
- for (len = bytes >> 2; len--; data += 4) {
- csum ^= ((data[0]) | (data[1]<<8) | (data[2]<<16) | (data[3]<<24));
- }
-
- switch (bytes & 3) {
- case 3: ul |= *data++ << 16;
- case 2: ul |= *data++ << 8;
- case 1: ul |= *data;
- }
- csum ^= ul;
-
- return csum;
- }
-
- LONG CAB_decompress(CABSTATE, ULONG bytes, int save) {
- struct xadArchiveInfo *ai = CAB(ai);
- struct xadMasterBase *xadMasterBase = CAB(xad);
-
- UBYTE buf[cfdata_SIZEOF], *data;
- UWORD inlen, len, outlen, cando;
- ULONG cksum;
- LONG err = XADERR_OK;
-
- /* here's an optimisation to prevent the re-decoding of a folder with an
- * error at some position in it. If a file or skip goes beyond the point
- * where we last got an error, then we won't bother going through it all
- * again, we'll just repeat the error.
- */
- if (CAB(current) == CAB(lastfolder)
- && (CAB(offset) + bytes) > CAB(lastoffset))
- return CAB(lasterror);
-
-
- while (bytes > 0) {
- /* cando = the max number of bytes we can do */
- cando = CAB(outlen);
- if (cando > bytes) cando = bytes;
- D(("CAB: decomp bytes=%ld cando=%ld\n", bytes, cando))
- if (cando && save) WRITE(CAB(outpos), cando); /* if cando != 0 */
- CAB(outpos) += cando;
- CAB(outlen) -= cando;
- bytes -= cando; if (!bytes) break;
-
- /* we only get here if we emptied the output buffer */
-
- /* read data header + data */
- inlen = outlen = 0;
- while (outlen == 0) {
- /* read the block header, skip the reserved part */
- READ(buf, cfdata_SIZEOF);
- SKIP(CAB(current)->data_res[CAB(split)]);
-
- /* we shouldn't get blocks over CAB_INPUTMAX in size */
- data = CAB(inbuf) + inlen;
- if ((inlen += (len = GETWORD(cfdata_CompressedSize))) > CAB_INPUTMAX)
- ERROR(INPUT);
-
- READ(data, len);
-
- /* perform checksum test on the block (if one is stored) */
- if ((cksum = GETLONG(cfdata_CheckSum)) != 0) {
- if (cksum != CAB_checksum(buf+4, 4, CAB_checksum(data, len, 0)))
- ERROR(CHECKSUM);
- }
-
- /* outlen=0 means this block was part of a split block */
- if ((outlen = GETWORD(cfdata_UncompressedSize)) == 0) {
- CAB(split)++; SEEK(CAB(current)->offsets[CAB(split)]);
- }
- }
-
- /* decompress block */
- if ((err = CAB(decompress)(cabstate, inlen, outlen))) goto exit_handler;
- CAB(outlen) = outlen;
- CAB(outpos) = CAB(outbuf);
- }
-
- exit_handler:
- if (err) {
- if (err == XADERR_INPUT
- || err == XADERR_ILLEGALDATA
- || err == XADERR_DECRUNCH
- || err == XADERR_CHECKSUM
- || err == XADERR_DATAFORMAT) {
- CAB(lasterror) = err;
- CAB(lastfolder) = CAB(current);
- CAB(lastoffset) = CAB(offset);
- }
-
- /* reset folder */
- CAB(current) = NULL;
- }
- return err;
- }
-
- ASM(LONG) SAVEDS CAB_UnArchive(REG(a0, struct xadArchiveInfo *ai), XADBASE) {
- struct CABstate *cabstate = (struct CABstate *) ai->xai_PrivateClient;
- struct xadFileInfo *file = ai->xai_CurFile;
- struct CABfolder *fol = CABFILEFOL(file);
- LONG err = XADERR_OK;
-
- CAB(ai) = ai;
- CAB(xad) = xadMasterBase;
-
- /* is a change of folder needed? do we need to reset the current folder? */
- if (fol != CAB(current) || file->xfi_DataPos < CAB(offset)) {
- UWORD comptype = fol->comp_type;
-
- /* if the archiver has changed, call the old archiver's free() function */
- if (CAB(free) && CAB(current) && ((comptype & cffoldCOMPTYPE_MASK)
- != (CAB(current)->comp_type & cffoldCOMPTYPE_MASK))) CAB(free)(cabstate);
-
- switch (comptype & cffoldCOMPTYPE_MASK) {
- case cffoldCOMPTYPE_NONE:
- CAB(decompress) = CAB_NONEdecompress;
- CAB(free) = NULL;
- break;
- case cffoldCOMPTYPE_MSZIP:
- CAB(decompress) = CAB_ZIPdecompress;
- CAB(free) = NULL;
- break;
-
- case cffoldCOMPTYPE_QUANTUM:
- CAB(decompress) = CAB_QTMdecompress;
- CAB(free) = CAB_QTMfree;
- err = CAB_QTMinit(cabstate, (comptype>>4) & 0xf, (comptype>>8) & 0x1f);
- break;
-
- case cffoldCOMPTYPE_LZX:
- CAB(decompress) = CAB_LZXdecompress;
- CAB(free) = CAB_LZXfree;
- err = CAB_LZXinit(cabstate, (comptype >> 8 & 0x1f));
- break;
-
- default:
- err = XADERR_NOTSUPPORTED;
- }
- if (err) goto exit_handler;
-
- /* initialisation OK, set current folder and reset offset */
- SEEK(fol->offsets[0]);
- CAB(current) = fol;
- CAB(offset) = 0;
- CAB(outlen) = 0; /* discard existing block */
- CAB(split) = 0;
- }
-
- if (file->xfi_DataPos > CAB(offset)) {
- D(("CAB: unarc skipping %ld bytes\n",file->xfi_DataPos-CAB(offset)))
- /* decode bytes and send them to /dev/null */
- if ((err = CAB_decompress(cabstate, file->xfi_DataPos-CAB(offset), 0)))
- return err;
- else
- CAB(offset) = file->xfi_DataPos;
- }
-
- /* decode bytes and save them */
- D(("CAB: unarc decoding %ld bytes\n",file->xfi_Size))
- if (!(err = CAB_decompress(cabstate, file->xfi_Size, 1)))
- CAB(offset) += file->xfi_Size;
-
- exit_handler:
- return err;
- }
-
-
- ASM(void) CAB_Free(REG(a0, struct xadArchiveInfo *ai), XADBASE) {
- struct CABstate *cabstate = (struct CABstate *) ai->xai_PrivateClient;
- struct CABfolder *f, *nf;
-
- if (!cabstate) return;
- if (CAB(free)) CAB(free)(cabstate); /* call archiver's free() function */
- for (f = CAB(folders); f; f = nf) { nf = f->next; FREE(f); }
- FREE(cabstate);
- ai->xai_PrivateClient = NULL;
- }
-
-
- /*--------------------------------------------------------------------------*/
- /* executable loader */
-
- ASM(BOOL) CABEXE_RecogData(REG(d0, ULONG size), REG(a0, UBYTE *d), XADBASE) {
- if (size < 20000 || d[0] != 'M' || d[1] != 'Z') return 0;
-
- /* word aligned code signature: 817C2404 "MSCF" (found at random, sorry) */
- for (d+=8, size-=8; size >= 12; d+=2, size-=2) {
- if (d[0]==0x81 && d[1]==0x7C && d[2]==0x24 && d[3]==0x04
- && d[4]=='M' && d[5]=='S' && d[6]=='C' && d[7]=='F')
- return 1;
-
- /* another revision: 817DDC "MSCF" */
- if (d[0]==0x81 && d[1]==0x7D && d[2]==0xDC
- && d[3]=='M' && d[4]=='S' && d[5]=='C' && d[6]=='F')
- return 1;
- }
- return 0;
- }
-
-
- #define CABEXE_START (55 * 1024) /* search from 55k (StartBTClick.exe) */
- #define CABEXE_END (150 * 1024) /* search to 150k (says dirk) */
-
- ASM(LONG) CABEXE_GetInfo(REG(a0, struct xadArchiveInfo *ai), XADBASE) {
- /* offset=0 as sentinel is OK; file has to start "MZ" to get here */
- ULONG filelen, readlen, offset = 0, i;
- UBYTE *buf, *p;
- LONG err;
-
- filelen = ai->xai_InSize;
- if ((readlen = filelen - CABEXE_START) > (CABEXE_END - CABEXE_START)) {
- readlen = CABEXE_END - CABEXE_START;
- }
-
- ALLOC(UBYTE *, buf, readlen);
- SKIP(CABEXE_START);
- READ(buf, readlen);
-
- readlen -= cfhead_SIZEOF;
- for (i=0, p=buf; i < readlen; i++, p++) {
-
- /* if we find a header */
- if (p[0]=='M' && p[1]=='S' && p[2]=='C' && p[3]=='F') {
- /* read the 'length of cab file and 'offset within cab file' */
- ULONG len = (p[8]) | (p[9]<<8) | (p[10]<<16) | (p[11]<<24);
- ULONG foff = (p[16]) | (p[17]<<8) | (p[18]<<16) | (p[19]<<24);
- /* if these lengths are consistent, we have a match! */
- if (len < filelen && foff < len) {
- offset = CABEXE_START + i;
- D(("CAB: exe offset=%ld\n",offset))
- goto exit_handler;
- }
- }
- }
- err = XADERR_DATAFORMAT;
-
- exit_handler:
- if (buf) FREE(buf);
-
- /* if we found a match, actually look at the archive */
- if (offset != 0) {
- SEEK(offset);
- err = CAB_GetInfo(ai, xadMasterBase);
- }
- return err;
- }
-
-
- /*--------------------------------------------------------------------------*/
-
- const struct xadClient CABEXE_Client = {
- NEXTCLIENT, XADCLIENT_VERSION, 6, CAB_VERSION, CAB_REVISION,
-
- 24576, /* first 24kb should have signature */
- XADCF_FILEARCHIVER|XADCF_FREEFILEINFO|XADCF_FREESKIPINFO|XADCF_NOCHECKSIZE,
- 0, "CAB MS-EXE",
-
- /* client functions */
- (BOOL (*)()) CABEXE_RecogData,
- (LONG (*)()) CABEXE_GetInfo,
- (LONG (*)()) CAB_UnArchive,
- (void (*)()) CAB_Free
- };
-
- const struct xadClient CAB_Client = {
- (struct xadClient *) &CABEXE_Client,
- XADCLIENT_VERSION, 6, CAB_VERSION, CAB_REVISION,
-
- 14,
- XADCF_FILEARCHIVER | XADCF_FREEFILEINFO | XADCF_FREESKIPINFO,
- 0, "CAB",
-
- /* client functions */
- (BOOL (*)()) CAB_RecogData,
- (LONG (*)()) CAB_GetInfo,
- (LONG (*)()) CAB_UnArchive,
- (void (*)()) CAB_Free
- };
-